package com.xinsoft.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinsoft.common.exception.BDException;
import com.xinsoft.entity.dto.*;
import com.xinsoft.entity.po.*;
import com.xinsoft.entity.vo.CusDevTestPointVo;
import com.xinsoft.service.*;
import com.xinsoft.mapper.CusTestPointMapper;
import com.xinsoft.utils.ExcelUtils;
import com.xinsoft.validator.ValidatorUtils;
import lombok.Synchronized;
import org.apache.commons.lang.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author hsm
* @description 针对表【cus_test_point(测点表)】的数据库操作Service实现
* @createDate 2023-07-06 17:52:41
*/
@Service
public class CusTestPointServiceImpl extends ServiceImpl<CusTestPointMapper, CusTestPoint>
    implements CusTestPointService{

    @Resource
    CusGatewayService cusGatewayService;

    @Resource
    CusDeviceService cusDeviceService;

    @Resource
    CusWarnRuleService cusWarnRuleService;

    @Resource
    SysDictionaryService sysDictionaryService;

    @Resource
    SysFileHisService sysFileHisService;




    @Override
    public IPage<CusDevTestPointVo> findPageListByParam(CusTestPointPageParam param) {
        //分页
        Page<CusDevTestPointVo> page = new Page<>(param.getCurrentPage(), param.getPageSize());
        //查询分页
        IPage<CusDevTestPointVo> pageList = this.baseMapper.findListByParam(page, param);

        return pageList;
    }

    @Override
    public List<CusDevTestPointVo> findListByParam(CusTestPointPageParam param) {
        return this.baseMapper.findListByParam(param);
    }


    @Override
    public CusTestPoint addCusTestPoint(CusTestPointDTO cusTestPointDTO) {
        //校验测点id是否重复
        QueryWrapper queryWrapper  =new QueryWrapper<>();
        queryWrapper.eq("device_id",cusTestPointDTO.getDeviceId());
        queryWrapper.eq("test_point_code",cusTestPointDTO.getTestPointCode());
        int count = count(queryWrapper);
        if(count!=0){
            throw new BDException("操作失败，改设备下测点id:"+cusTestPointDTO.getTestPointCode()+"已存在，请无重复！");
        }

        CusTestPoint cusTestPoint = new CusTestPoint();
        BeanUtils.copyProperties(cusTestPointDTO,cusTestPoint);
        save(cusTestPoint);
        return cusTestPoint;
    }

    @Override
    public CusTestPoint editCusTestPoint(CusTestPointDTO cusTestPointDTO) {
        //校验测点id是否重复
        QueryWrapper queryWrapper  =new QueryWrapper<>();
        queryWrapper.eq("device_id",cusTestPointDTO.getDeviceId());
        queryWrapper.eq("test_point_code",cusTestPointDTO.getTestPointCode());
        queryWrapper.ne("id",cusTestPointDTO.getId());
        int count = count(queryWrapper);
        if(count!=0){
            throw new BDException("操作失败，该设备下测点id:"+cusTestPointDTO.getTestPointCode()+"已存在，请勿重复！");
        }
        CusTestPoint cusTestPoint = new CusTestPoint();
        BeanUtils.copyProperties(cusTestPointDTO,cusTestPoint);
        updateById(cusTestPoint);
        return cusTestPoint;
    }
    @Override
    public void del(List<Integer> ids) {
        removeByIds(ids);
    }

    @Override
    public CusDevTestPointVo getCusTestPoint(Integer id) {
        return this.baseMapper.findTestPointInfo(id);
    }

    @Override
    public IPage<CusDevTestPointVo> testPointListByRuleId(CusTestPointPageParam param) {
        //分页
        Page<CusDevTestPointVo> page = new Page<>(param.getCurrentPage(), param.getPageSize());
        //查询分页
        IPage<CusDevTestPointVo> pageList = this.baseMapper.findListByWarnRuleId(page, param);

        return pageList;
    }




    @Override
    @Synchronized
    public JSONObject importExcel(MultipartFile multipartFile) throws IOException {
        // 初始化错误行信息list，用来记录导入失败的rowNum
        List<ExcelErrRowDTO> errRowDOs = new ArrayList<>();

        // 对excel是否为空进行check
        if (multipartFile.isEmpty()) {
            throw new BDException("导入失败，请选择文件！");
        }

        //设置excel参数
        ImportParams params = new ImportParams();
        params.setTitleRows(1);
        params.setHeadRows(1);
        List<CusTestPointImportDTO> cusTestPointList;
        List<CusTestPoint> cusTestPoints = CollectionUtil.newArrayList();

        // 解析excel中的行，cusTestPointList
        try {
            // 解析excel
            cusTestPointList = ExcelImportUtil.importExcel(multipartFile.getInputStream(), CusTestPointImportDTO.class, params);
        } catch (Exception e) {
            throw new BDException("导入失败，文件内容解析错误！");
        }
        JSONObject result = new JSONObject();

        //校验
        if (cusTestPointList.size() > 0) {
            //取出excel和db中所有重复的测点编码

            //获取excel中所有的username
            List<String> devicePointIdList = CollectionUtil.newArrayList();
            for (CusTestPointImportDTO cusTestPointImportDTO : cusTestPointList) {
                String devicePointId=  cusTestPointImportDTO.getDeviceName() +"@"+cusTestPointImportDTO.getTestPointCode();
                devicePointIdList.add(devicePointId);
            }


            //获取系统中所有的devicePointId
            List<String> dbDevicePointIdList = this.getAllDevicePointId();
            // 存放存在重复的devicePointId，用于定位重复存放存在重复的devicePointId的行
            List<String> duplicateDevicePointIds = new ArrayList<>();

            if (dbDevicePointIdList.size() > 0 && dbDevicePointIdList.size() > 0) {
                //合并
                dbDevicePointIdList.addAll(devicePointIdList);
                //取出存在重复的DevicePointId
                duplicateDevicePointIds = ExcelUtils.getDuplicateElements(dbDevicePointIdList);
            }

            //网关
            List<CusGateway> gatewayList = cusGatewayService.list();
            Map<String, Integer> gatewayMap = gatewayList.stream()
                    .collect(Collectors.toMap(CusGateway::getGatewayName, CusGateway::getId, (v1, v2) -> v2));

            //设备
            List<CusDevice> deviceList = cusDeviceService.list();
            Map<String, Integer> deviceMap = deviceList.stream()
                    .collect(Collectors.toMap(CusDevice::getDeviceName, CusDevice::getId, (v1, v2) -> v2));

            //预警规则
            List<CusWarnRule> cusWarnRuleList = cusWarnRuleService.list();
            Map<String, Integer> cusWarnRuleMap = cusWarnRuleList.stream()
                    .collect(Collectors.toMap(CusWarnRule::getRuleName, CusWarnRule::getId, (v1, v2) -> v2));

            // 读写类型 rw_type
            List<SysDictionary> rwTypeList =  sysDictionaryService.getDictByTypeCode("rw_type");
            Map<String, Integer>  rwTypeMap = rwTypeList.stream()
                    .collect(Collectors.toMap(SysDictionary::getDicName, SysDictionary::getId, (v1, v2) -> v2));

            // 子类型 数据字典 measuring_point_child_type
            List<SysDictionary> chileTypeList =  sysDictionaryService.getDictByTypeCode("measuring_point_child_type");
            Map<String, Integer>  chileTypeMap = chileTypeList.stream()
                    .collect(Collectors.toMap(SysDictionary::getDicName, SysDictionary::getId, (v1, v2) -> v2));

            // 测点单位 数据字典 measuring_point_uom
            List<SysDictionary> pointUomList =  sysDictionaryService.getDictByTypeCode("measuring_point_uom");
            Map<String, Integer>  pointUomMap = pointUomList.stream()
                    .collect(Collectors.toMap(SysDictionary::getDicName, SysDictionary::getId, (v1, v2) -> v2));

            // 使用类别 数据字典 use_type
            List<SysDictionary> useTypeList =  sysDictionaryService.getDictByTypeCode("use_type");
            Map<String, Integer>  useTypeMap = useTypeList.stream()
                    .collect(Collectors.toMap(SysDictionary::getDicName, SysDictionary::getId, (v1, v2) -> v2));

            // 授权方式 impower_type
            List<SysDictionary> impowerTypeList =  sysDictionaryService.getDictByTypeCode("impower_type");
            Map<String, Integer>  impowerTypeMap = impowerTypeList.stream()
                    .collect(Collectors.toMap(SysDictionary::getDicName, SysDictionary::getId, (v1, v2) -> v2));

            // 格式（小数位数） format
            List<SysDictionary> formatList =  sysDictionaryService.getDictByTypeCode("format");
            Map<String, Integer>  formatMap = formatList.stream()
                    .collect(Collectors.toMap(SysDictionary::getDicName, SysDictionary::getId, (v1, v2) -> v2));


            int index = 1;

            for (CusTestPointImportDTO cusTestPointImportDTO : cusTestPointList) {
                index ++;
                // check
                StringBuilder stringBuilder = new StringBuilder();
                ExcelErrRowDTO excelErrRowDO= new ExcelErrRowDTO();

                // 参数校验
                stringBuilder.append(ValidatorUtils.validateExcel(cusTestPointImportDTO));

                // 检验devicePointId 是否重复
                if(duplicateDevicePointIds.contains(cusTestPointImportDTO.getDeviceName()+"@"+cusTestPointImportDTO.getTestPointCode())){
                    stringBuilder.append("此设备下该测点id已经存在，请勿重复！");
                }



                // 网关
                if(StringUtils.isNotEmpty(cusTestPointImportDTO.getGatewayName())){
                    Integer gateWayId = gatewayMap.get(cusTestPointImportDTO.getGatewayName());
                    if(gateWayId==null){
                        stringBuilder.append("网关:"+cusTestPointImportDTO.getGatewayName()+",在系统中不存在！");
                    }
                    cusTestPointImportDTO.setGatewayId(gateWayId);
                }

                //设备
                if(StringUtils.isNotEmpty(cusTestPointImportDTO.getDeviceName())){
                    Integer deviceId = deviceMap.get(cusTestPointImportDTO.getDeviceName());
                    if(deviceId==null){
                        stringBuilder.append("设备:"+cusTestPointImportDTO.getDeviceName()+",在系统中不存在！");
                    }
                    cusTestPointImportDTO.setDeviceId(deviceId);
                }

                //预警规则I
                if(StringUtils.isNotEmpty(cusTestPointImportDTO.getWarnRuleName())){
                    Integer warnId = cusWarnRuleMap.get(cusTestPointImportDTO.getWarnRuleName());
                    if(warnId==null){
                        stringBuilder.append("预警规则:"+cusTestPointImportDTO.getWarnRuleName()+",在系统中不存在！");
                    }
                    cusTestPointImportDTO.setWarnRuleId(warnId);
                }

                //读写类型
                if(StringUtils.isNotEmpty(cusTestPointImportDTO.getRwTypeName())){
                    Integer rwType = rwTypeMap.get(cusTestPointImportDTO.getRwTypeName());
                    if(rwType==null){
                        stringBuilder.append("读写类型:"+cusTestPointImportDTO.getRwTypeName()+",在系统中不存在！");
                    }
                    cusTestPointImportDTO.setRwType(rwType);
                }

                //子类型
                if(StringUtils.isNotEmpty(cusTestPointImportDTO.getTestPointTypeName())){
                    Integer testPointType = chileTypeMap.get(cusTestPointImportDTO.getTestPointTypeName());
                    if(testPointType==null){
                        stringBuilder.append("子类型:"+cusTestPointImportDTO.getTestPointTypeName()+",在系统中不存在！");
                    }
                    cusTestPointImportDTO.setTestPointType(testPointType);
                }

                //测点单位
                if(StringUtils.isNotEmpty(cusTestPointImportDTO.getTestPointUnitName())){
                    Integer unitId = pointUomMap.get(cusTestPointImportDTO.getTestPointUnitName());
                    if(unitId==null){
                        stringBuilder.append("测点单位:"+cusTestPointImportDTO.getTestPointUnitName()+",在系统中不存在！");
                    }
                    cusTestPointImportDTO.setTestPointUnit(unitId);
                }

                //使用类别
                if(StringUtils.isNotEmpty(cusTestPointImportDTO.getUseTypeName())){
                    Integer useTypeId = useTypeMap.get(cusTestPointImportDTO.getUseTypeName());
                    if(useTypeId==null){
                        stringBuilder.append("使用类别:"+cusTestPointImportDTO.getUseTypeName()+",在系统中不存在！");
                    }
                    cusTestPointImportDTO.setUseType(useTypeId);
                }

                //授权方式 impower_type
                if(StringUtils.isNotEmpty(cusTestPointImportDTO.getImpowerName())){
                    Integer impowerType = impowerTypeMap.get(cusTestPointImportDTO.getImpowerName());
                    if(impowerType==null){
                        stringBuilder.append("授权方式:"+cusTestPointImportDTO.getImpowerName()+",在系统中不存在！");
                    }
                    cusTestPointImportDTO.setImpower(impowerType);
                }

                //格式
                if(StringUtils.isNotEmpty(cusTestPointImportDTO.getTpFormatName())){
                    Integer format = formatMap.get(cusTestPointImportDTO.getTpFormatName());
                    if(format==null){
                        stringBuilder.append("格式:"+cusTestPointImportDTO.getTpFormat()+",在系统中不存在！");
                    }
                    cusTestPointImportDTO.setTpFormat(format);
                }

                // 是否手动输入 0:否，1:是
                if(StringUtils.equals(cusTestPointImportDTO.getDoManualInputName(),"是")){
                    cusTestPointImportDTO.setDoManualInput(1);
                }else{
                    cusTestPointImportDTO.setDoManualInput(0);
                }

                // 是否虚拟点 0:否，1:是
                if(StringUtils.equals(cusTestPointImportDTO.getDoVirtualPointName(),"是")){
                    cusTestPointImportDTO.setDoVirtualPoint(1);
                }else{
                    cusTestPointImportDTO.setDoVirtualPoint(0);
                }

                // 是否预警 0:否，1:是
                if(StringUtils.equals(cusTestPointImportDTO.getDoWarnName(),"是")){
                    cusTestPointImportDTO.setDoWarn(1);
                }else{
                    cusTestPointImportDTO.setDoWarn(0);
                }


                // 将错误行信息保存到list
                String errMsg = stringBuilder.toString();
                if(StringUtils.isNotEmpty(errMsg)){
                    excelErrRowDO.setRowIndex(index);
                    excelErrRowDO.setErrMessage(errMsg);
                    errRowDOs.add(excelErrRowDO);
                    continue;
                }
                //保存
                CusTestPoint cusTestPoint = new CusTestPoint();
                BeanUtils.copyProperties(cusTestPointImportDTO,cusTestPoint);
                cusTestPoints.add(cusTestPoint);
            }
            //批量保存
            saveBatch(cusTestPoints);
            String errFileUrl = ExcelUtils.exportErrRows(errRowDOs,multipartFile,sysFileHisService);

            result.put("errFileUrl",errFileUrl);
            return result;
        }
        return result;
    }

    private List<String> getAllDevicePointId() {
        List<String> list = this.baseMapper.findDevicePointId();
        return list;
    }

}




